package com.gitee.wsl.doc.prosemirror.ui.inputrule

import com.gitee.wsl.doc.prosemirror.model.mark.MarkType
import com.gitee.wsl.doc.prosemirror.model.node.ext.markApplies
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.Transaction
import com.gitee.wsl.doc.prosemirror.state.selection.SelectionRange
import com.gitee.wsl.doc.prosemirror.transform.ext.addMark
import com.gitee.wsl.doc.prosemirror.transform.ext.replaceWith
import com.gitee.wsl.doc.prosemirror.ui.inputrule.InputRule.Options

class MarkInputRule(
    matcher: Regex,
    markType: MarkType,
    options: Options = Options()
) : InputRule(
    match = matcher,
    handler = MarkHandler(markType),
    options = options
)


fun InputRule.Companion.mark(matcher: Regex,
                             markType: MarkType,
                             options: Options = Options()) = MarkInputRule(matcher,markType,options)

private class MarkHandler(val markType: MarkType):InputRuleHandler{
    override fun execute(
        state: EditorState,
        match: MatchResult,
        start: Int,
        end: Int,
    ): Transaction? {
        // 确定标记是否适用于匹配
        val startPos = state.doc.resolve(start)
        val endPos = state.doc.resolve(end)
        val range = listOf(SelectionRange(startPos, endPos))

        if (!state.doc.markApplies( range, markType)) {
            return null
        }

        // 列出所有现有标记并添加新标记
        val existingMarks = state.doc.nodeAt(start)?.marks?.map { it.type } ?: emptyList()
        val newMarks = existingMarks.toMutableList().apply { add(markType) }

        // 用匹配的文本替换受影响的范围 - 这会移除例如斜体周围的星号
        val tr = state.tr.replaceWith(
            start,
            end,
            markType.schema.text(match.groupValues[1])
        )

        // 添加回所有标记，包括新标记
        for (mark in newMarks) {
            tr.addMark(
                tr.mapping.map(start),
                tr.mapping.map(end),
                mark.create(null)
            )
        }

        // 使文本编辑器在下次输入时插入没有标记的干净文本
        for (mark in newMarks) {
            tr.removeStoredMark(mark)
        }

        // 如果最后一个字符不是换行符，则添加回它，
        // 否则省略它，因为换行符在文本节点之外处理
        if (match.groupValues.getOrNull(2) != "\n") {
            tr.insertText(match.groupValues.getOrNull(2) ?: "")
        }

        return tr
    }
}